placesview: implement available space
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Tue, 3 Nov 2015 02:50:06 +0000 (00:50 -0200)
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Wed, 9 Dec 2015 22:30:10 +0000 (20:30 -0200)
GtkPlacesView is a widget to display locations
in the computer, such as root ("/") and volumes,
separating the persistent devices from removable
ones.

From the latest mockups[1], GtkPlacesView would
display the available space of local drives like
partitions. This, however, is not implemented in
the current codebase.

Fix that by implementing the measurement of disk
space, and adding a new property GtkPlacesView::show-disk-usage
which controls the visibility of measured disks.

[1] https://raw.githubusercontent.com/gnome-design-team/gnome-mockups/master/nautilus/nautilus-next/other-locations.png

https://bugzilla.gnome.org/show_bug.cgi?id=759225

gtk/gtkplacesview.c
gtk/gtkplacesviewrow.c
gtk/gtkplacesviewrowprivate.h
gtk/ui/gtkplacesviewrow.ui

index 011334b8034f3cd3e28236c480bb9fbe2f54f95d..958887732f13e5b6d23955ae112b06f3737c1005 100644 (file)
@@ -73,6 +73,7 @@ struct _GtkPlacesViewPrivate
   GtkWidget                     *network_placeholder_label;
 
   GtkSizeGroup                  *path_size_group;
+  GtkSizeGroup                  *space_size_group;
 
   GtkEntryCompletion            *address_entry_completion;
   GtkListStore                  *completion_store;
@@ -405,6 +406,7 @@ gtk_places_view_finalize (GObject *object)
   g_clear_object (&priv->cancellable);
   g_clear_object (&priv->networks_fetching_cancellable);
   g_clear_object (&priv->path_size_group);
+  g_clear_object (&priv->space_size_group);
 
   G_OBJECT_CLASS (gtk_places_view_parent_class)->finalize (object);
 }
@@ -674,6 +676,7 @@ insert_row (GtkPlacesView *view,
                     row);
 
   gtk_places_view_row_set_path_size_group (GTK_PLACES_VIEW_ROW (row), priv->path_size_group);
+  gtk_places_view_row_set_space_size_group (GTK_PLACES_VIEW_ROW (row), priv->space_size_group);
 
   gtk_container_add (GTK_CONTAINER (priv->listbox), row);
 }
@@ -2258,6 +2261,7 @@ gtk_places_view_init (GtkPlacesView *self)
   priv->volume_monitor = g_volume_monitor_get ();
   priv->open_flags = GTK_PLACES_OPEN_NORMAL;
   priv->path_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  priv->space_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
   gtk_widget_init_template (GTK_WIDGET (self));
 }
index f6d5658f51616d285f7c6cfaaafd39bc60508afb..d797c18e8a8178e118333113382b68f6e4ac4bda 100644 (file)
@@ -42,6 +42,7 @@ struct _GtkPlacesViewRow
 {
   GtkListBoxRow  parent_instance;
 
+  GtkLabel      *available_space_label;
   GtkSpinner    *busy_spinner;
   GtkButton     *eject_button;
   GtkImage      *eject_icon;
@@ -54,6 +55,8 @@ struct _GtkPlacesViewRow
   GMount        *mount;
   GFile         *file;
 
+  GCancellable  *cancellable;
+
   gint           is_network : 1;
 };
 
@@ -73,14 +76,124 @@ enum {
 
 static GParamSpec *properties [LAST_PROP];
 
+static void
+measure_available_space_finished (GObject      *object,
+                                  GAsyncResult *res,
+                                  gpointer      user_data)
+{
+  GtkPlacesViewRow *row = user_data;
+  GFileInfo *info;
+  GError *error;
+  guint64 free_space;
+  guint64 total_space;
+  gchar *formatted_free_size;
+  gchar *formatted_total_size;
+  gchar *label;
+
+  error = NULL;
+
+  info = g_file_query_filesystem_info_finish (G_FILE (object),
+                                              res,
+                                              &error);
+
+  if (error)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+          !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED))
+        {
+          g_warning ("Failed to measure available space: %s", error->message);
+        }
+
+      g_clear_error (&error);
+      goto out;
+    }
+
+  if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE) ||
+      !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE))
+    {
+      g_object_unref (info);
+      goto out;
+    }
+
+  free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+  total_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
+
+  formatted_free_size = g_format_size (free_space);
+  formatted_total_size = g_format_size (total_space);
+  /* Translators: respectively, free and total space of the drive */
+  label = g_strdup_printf (_("%s / %s available"), formatted_free_size, formatted_total_size);
+
+  gtk_label_set_label (row->available_space_label, label);
+
+  g_object_unref (info);
+  g_free (formatted_total_size);
+  g_free (formatted_free_size);
+  g_free (label);
+out:
+  g_object_unref (object);
+}
+
+static void
+measure_available_space (GtkPlacesViewRow *row)
+{
+  gboolean should_measure;
+
+  should_measure = (!row->is_network && (row->volume || row->mount || row->file));
+
+  gtk_label_set_label (row->available_space_label, "");
+  gtk_widget_set_visible (GTK_WIDGET (row->available_space_label), should_measure);
+
+  if (should_measure)
+    {
+      GFile *file = NULL;
+
+      if (row->file)
+        {
+          file = g_object_ref (row->file);
+        }
+      else if (row->mount)
+        {
+          file = g_mount_get_root (row->mount);
+        }
+      else if (row->volume)
+        {
+          GMount *mount;
+
+          mount = g_volume_get_mount (row->volume);
+
+          if (mount)
+            file = g_mount_get_root (row->mount);
+
+          g_clear_object (&mount);
+        }
+
+      if (file)
+        {
+          g_cancellable_cancel (row->cancellable);
+          g_clear_object (&row->cancellable);
+          row->cancellable = g_cancellable_new ();
+
+          g_file_query_filesystem_info_async (file,
+                                              G_FILE_ATTRIBUTE_FILESYSTEM_FREE "," G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
+                                              G_PRIORITY_DEFAULT,
+                                              row->cancellable,
+                                              measure_available_space_finished,
+                                              row);
+        }
+    }
+}
+
 static void
 gtk_places_view_row_finalize (GObject *object)
 {
   GtkPlacesViewRow *self = GTK_PLACES_VIEW_ROW (object);
 
+  g_cancellable_cancel (self->cancellable);
+
   g_clear_object (&self->volume);
   g_clear_object (&self->mount);
   g_clear_object (&self->file);
+  g_clear_object (&self->cancellable);
 
   G_OBJECT_CLASS (gtk_places_view_row_parent_class)->finalize (object);
 }
@@ -172,14 +285,17 @@ gtk_places_view_row_set_property (GObject      *object,
        * size but it stays hidden when needed.
        */
       gtk_widget_set_child_visible (GTK_WIDGET (self->eject_button), self->mount != NULL);
+      measure_available_space (self);
       break;
 
     case PROP_FILE:
       g_set_object (&self->file, g_value_get_object (value));
+      measure_available_space (self);
       break;
 
     case PROP_IS_NETWORK:
       gtk_places_view_row_set_is_network (self, g_value_get_boolean (value));
+      measure_available_space (self);
       break;
 
     default:
@@ -250,6 +366,7 @@ gtk_places_view_row_class_init (GtkPlacesViewRowClass *klass)
 
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkplacesviewrow.ui");
 
+  gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, available_space_label);
   gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, busy_spinner);
   gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, eject_button);
   gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, eject_icon);
@@ -352,3 +469,11 @@ gtk_places_view_row_set_path_size_group (GtkPlacesViewRow *row,
   if (group)
     gtk_size_group_add_widget (group, GTK_WIDGET (row->path_label));
 }
+
+void
+gtk_places_view_row_set_space_size_group (GtkPlacesViewRow *row,
+                                          GtkSizeGroup     *group)
+{
+  if (group)
+    gtk_size_group_add_widget (group, GTK_WIDGET (row->available_space_label));
+}
index 5389676d128348e9cb12f91563a104f38c7a95f5..0233188977f0a09fc651221797492a756f27552d 100644 (file)
@@ -54,9 +54,17 @@ gboolean           gtk_places_view_row_get_is_network            (GtkPlacesViewR
 void               gtk_places_view_row_set_is_network            (GtkPlacesViewRow   *row,
                                                                   gboolean            is_network);
 
+gboolean           gtk_places_view_row_get_show_disk_usage       (GtkPlacesViewRow   *row);
+
+void               gtk_places_view_row_set_show_disk_usage       (GtkPlacesViewRow   *row,
+                                                                  gboolean            show_disk_usage);
+
 void               gtk_places_view_row_set_path_size_group       (GtkPlacesViewRow   *row,
                                                                   GtkSizeGroup       *group);
 
+void               gtk_places_view_row_set_space_size_group      (GtkPlacesViewRow   *row,
+                                                                  GtkSizeGroup       *group);
+
 G_END_DECLS
 
 #endif /* GTK_PLACES_VIEW_ROW_H */
index 8c888f0be829c30e7614d08adcbb486f24a2ae7a..89c840416d579f95ae9d44273d91bb865cda9752 100644 (file)
                 <property name="visible">1</property>
                 <property name="hexpand">1</property>
                 <property name="xalign">0</property>
+                <property name="ellipsize">end</property>
               </object>
               <packing>
                 <property name="position">1</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkLabel" id="available_space_label">
+                <property name="visible">False</property>
+                <property name="xalign">1</property>
+                <style>
+                  <class name="dim-label" />
+                </style>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkLabel" id="path_label">
                 <property name="visible">1</property>
@@ -44,7 +57,7 @@
                 </style>
               </object>
               <packing>
-                <property name="position">2</property>
+                <property name="position">3</property>
               </packing>
             </child>
             <child>
@@ -66,7 +79,7 @@
                 </style>
               </object>
               <packing>
-                <property name="position">3</property>
+                <property name="position">4</property>
               </packing>
             </child>
             <child>
@@ -74,7 +87,7 @@
                 <property name="active">1</property>
               </object>
               <packing>
-                <property name="position">4</property>
+                <property name="position">5</property>
               </packing>
             </child>
           </object>